1   /*
2    * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /*
25   * @test
26   * @bug     4906359 6239296
27   * @summary Basic test for content-based array object methods
28   * @author  Josh Bloch, Martin Buchholz
29   */
30  
31  import java.util.*;
32  import java.io.*;
33  
34  public class ArrayObjectMethods {
35      int[] sizes = {0, 10, 100, 200, 1000};
36  
37      void test(String[] args) throws Throwable {
38          equal(Arrays.deepToString(null), "null");
39          equal(Arrays.deepToString(new Object[]{}), "[]");
40          equal(Arrays.deepToString(new Object[]{null}), "[null]");
41          equal(Arrays.deepToString(new Object[]{null, 1}), "[null, 1]");
42          equal(Arrays.deepToString(new Object[]{1, null}), "[1, null]");
43          equal(Arrays.deepToString(new Object[]{new Object[]{}, null}), "[[], null]");
44  
45          {
46              Object[] a = {1, null};
47              a[1] = a;
48              equal(Arrays.deepToString(a), "[1, [...]]");
49              a[0] = a;
50              equal(Arrays.deepToString(a), "[[...], [...]]");
51              a[0] = a[1] = new Object[]{1, null, a};
52              equal(Arrays.deepToString(a), "[[1, null, [...]], [1, null, [...]]]");
53          }
54  
55          for (int size : sizes) {
56              {
57                  long[] a = Rnd.longArray(size);
58                  equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
59                  equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
60              }
61              {
62                  int[] a = Rnd.intArray(size);
63                  equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
64                  equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
65              }
66              {
67                  short[] a = Rnd.shortArray(size);
68                  equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
69                  equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
70              }
71              {
72                  char[] a = Rnd.charArray(size);
73                  equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
74                  equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
75              }
76              {
77                  byte[] a = Rnd.byteArray(size);
78                  equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
79                  equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
80              }
81              {
82                  boolean[] a = Rnd.booleanArray(size);
83                  equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
84                  equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
85              }
86              {
87                  double[] a = Rnd.doubleArray(size);
88                  equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
89                  equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
90              }
91              {
92                  float[] a = Rnd.floatArray(size);
93                  equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
94                  equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
95              }
96              {
97                  Object[] a = Rnd.flatObjectArray(size);
98                  equal(Arrays.toString(a), Arrays.asList(a).toString());
99                  equal(Arrays.deepToString(a), Arrays.asList(a).toString());
100                 equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
101             }
102 
103             if (size <= 200) {
104                 Object[] a = Rnd.nestedObjectArray(size);
105                 List aList = deepToList(a);
106                 equal(Arrays.toString(a), Arrays.asList(a).toString());
107                 equal(Arrays.deepToString(a), aList.toString());
108                 equal(Arrays.deepHashCode(a), aList.hashCode());
109                 equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
110 
111                 Object[] deepCopy = (Object[]) deepCopy(a);
112                 check(Arrays.deepEquals(a, deepCopy));
113                 check(Arrays.deepEquals(deepCopy, a));
114 
115                 // Make deepCopy != a
116                 if (size == 0)
117                     deepCopy = new Object[] {"foo"};
118                 else if (deepCopy[deepCopy.length - 1] == null)
119                     deepCopy[deepCopy.length - 1] = "baz";
120                 else
121                     deepCopy[deepCopy.length - 1] = null;
122                 check(! Arrays.deepEquals(a, deepCopy));
123                 check(! Arrays.deepEquals(deepCopy, a));
124             }
125         }
126     }
127 
128     // Utility method to turn an array into a list "deeply," turning
129     // all primitives into objects
130     List<Object> deepToList(Object[] a) {
131         List<Object> result = new ArrayList<Object>();
132         for (Object e : a) {
133             if (e instanceof byte[])
134                 result.add(PrimitiveArrays.asList((byte[])e));
135             else if (e instanceof short[])
136                 result.add(PrimitiveArrays.asList((short[])e));
137             else if (e instanceof int[])
138                 result.add(PrimitiveArrays.asList((int[])e));
139             else if (e instanceof long[])
140                 result.add(PrimitiveArrays.asList((long[])e));
141             else if (e instanceof char[])
142                 result.add(PrimitiveArrays.asList((char[])e));
143             else if (e instanceof double[])
144                 result.add(PrimitiveArrays.asList((double[])e));
145             else if (e instanceof float[])
146                 result.add(PrimitiveArrays.asList((float[])e));
147             else if (e instanceof boolean[])
148                 result.add(PrimitiveArrays.asList((boolean[])e));
149             else if (e instanceof Object[])
150                 result.add(deepToList((Object[])e));
151             else
152                 result.add(e);
153         }
154         return result;
155     }
156 
157     // Utility method to do a deep copy of an object *very slowly* using
158     // serialization/deserialization
159     Object deepCopy(Object oldObj) {
160         try {
161             ByteArrayOutputStream bos = new ByteArrayOutputStream();
162             ObjectOutputStream oos = new ObjectOutputStream(bos);
163             oos.writeObject(oldObj);
164             oos.flush();
165             ByteArrayInputStream bin = new ByteArrayInputStream(
166                 bos.toByteArray());
167             ObjectInputStream ois = new ObjectInputStream(bin);
168             return ois.readObject();
169         } catch(Exception e) {
170             throw new IllegalArgumentException(e);
171         }
172     }
173 
174     //--------------------- Infrastructure ---------------------------
175     volatile int passed = 0, failed = 0;
176     void pass() {passed++;}
177     void fail() {failed++; Thread.dumpStack();}
178     void fail(String msg) {System.err.println(msg); fail();}
179     void unexpected(Throwable t) {failed++; t.printStackTrace();}
180     void check(boolean cond) {if (cond) pass(); else fail();}
181     void equal(Object x, Object y) {
182         if (x == null ? y == null : x.equals(y)) pass();
183         else fail(x + " not equal to " + y);}
184     public static void main(String[] args) throws Throwable {
185         new ArrayObjectMethods().instanceMain(args);}
186     void instanceMain(String[] args) throws Throwable {
187         try {test(args);} catch (Throwable t) {unexpected(t);}
188         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
189         if (failed > 0) throw new AssertionError("Some tests failed");}
190 }
191 
192 /**
193  * Methods to generate "interesting" random primitives and primitive
194  * arrays.  Unlike Random.nextXxx, these methods return small values
195  * and boundary values (e.g., 0, -1, NaN) with greater than normal
196  * likelihood.
197  */
198 
199 class Rnd {
200     private static Random rnd = new Random();
201 
202     public static long nextLong() {
203         switch(rnd.nextInt(10)) {
204             case 0:  return 0;
205             case 1:  return Long.MIN_VALUE;
206             case 2:  return Long.MAX_VALUE;
207             case 3: case 4: case 5:
208                      return (long) (rnd.nextInt(20) - 10);
209             default: return rnd.nextLong();
210         }
211     }
212 
213     public static int nextInt() {
214         switch(rnd.nextInt(10)) {
215             case 0:  return 0;
216             case 1:  return Integer.MIN_VALUE;
217             case 2:  return Integer.MAX_VALUE;
218             case 3: case 4: case 5:
219                      return rnd.nextInt(20) - 10;
220             default: return rnd.nextInt();
221         }
222     }
223 
224     public static short nextShort() {
225         switch(rnd.nextInt(10)) {
226             case 0:  return 0;
227             case 1:  return Short.MIN_VALUE;
228             case 2:  return Short.MAX_VALUE;
229             case 3: case 4: case 5:
230                      return (short) (rnd.nextInt(20) - 10);
231             default: return (short) rnd.nextInt();
232         }
233     }
234 
235     public static char nextChar() {
236         switch(rnd.nextInt(10)) {
237             case 0:  return 0;
238             case 1:  return Character.MIN_VALUE;
239             case 2:  return Character.MAX_VALUE;
240             case 3: case 4: case 5:
241                      return (char) (rnd.nextInt(20) - 10);
242             default: return (char) rnd.nextInt();
243         }
244     }
245 
246     public static byte nextByte() {
247         switch(rnd.nextInt(10)) {
248             case 0:  return 0;
249             case 1:  return Byte.MIN_VALUE;
250             case 2:  return Byte.MAX_VALUE;
251             case 3: case 4: case 5:
252                      return (byte) (rnd.nextInt(20) - 10);
253             default: return (byte) rnd.nextInt();
254         }
255     }
256 
257     public static boolean nextBoolean() {
258         return rnd.nextBoolean();
259     }
260 
261     public static double nextDouble() {
262         switch(rnd.nextInt(20)) {
263             case 0:  return 0;
264             case 1:  return -0.0;
265             case 2:  return Double.MIN_VALUE;
266             case 3:  return Double.MAX_VALUE;
267             case 4:  return Double.NaN;
268             case 5:  return Double.NEGATIVE_INFINITY;
269             case 6:  return Double.POSITIVE_INFINITY;
270             case 7: case 8: case 9:
271                      return (rnd.nextInt(20) - 10);
272             default: return rnd.nextDouble();
273         }
274     }
275 
276     public static float nextFloat() {
277         switch(rnd.nextInt(20)) {
278             case 0:  return 0;
279             case 1:  return -0.0f;
280             case 2:  return Float.MIN_VALUE;
281             case 3:  return Float.MAX_VALUE;
282             case 4:  return Float.NaN;
283             case 5:  return Float.NEGATIVE_INFINITY;
284             case 6:  return Float.POSITIVE_INFINITY;
285             case 7: case 8: case 9:
286                      return (rnd.nextInt(20) - 10);
287             default: return rnd.nextFloat();
288         }
289     }
290 
291     public static Object nextObject() {
292         switch(rnd.nextInt(10)) {
293             case 0:  return null;
294             case 1:  return "foo";
295             case 2:  case 3: case 4:
296                      return Double.valueOf(nextDouble());
297             default: return Integer.valueOf(nextInt());
298         }
299     }
300 
301     public static long[] longArray(int length) {
302         long[] result = new long[length];
303         for (int i = 0; i < length; i++)
304             result[i] = Rnd.nextLong();
305         return result;
306     }
307 
308     public static int[] intArray(int length) {
309         int[] result = new int[length];
310         for (int i = 0; i < length; i++)
311             result[i] = Rnd.nextInt();
312         return result;
313     }
314 
315     public static short[] shortArray(int length) {
316         short[] result = new short[length];
317         for (int i = 0; i < length; i++)
318             result[i] = Rnd.nextShort();
319         return result;
320     }
321 
322     public static char[] charArray(int length) {
323         char[] result = new char[length];
324         for (int i = 0; i < length; i++)
325             result[i] = Rnd.nextChar();
326         return result;
327     }
328 
329     public static byte[] byteArray(int length) {
330         byte[] result = new byte[length];
331         for (int i = 0; i < length; i++)
332             result[i] = Rnd.nextByte();
333         return result;
334     }
335 
336     public static boolean[] booleanArray(int length) {
337         boolean[] result = new boolean[length];
338         for (int i = 0; i < length; i++)
339             result[i] = Rnd.nextBoolean();
340         return result;
341     }
342 
343     public static double[] doubleArray(int length) {
344         double[] result = new double[length];
345         for (int i = 0; i < length; i++)
346             result[i] = Rnd.nextDouble();
347         return result;
348     }
349 
350     public static float[] floatArray(int length) {
351         float[] result = new float[length];
352         for (int i = 0; i < length; i++)
353             result[i] = Rnd.nextFloat();
354         return result;
355     }
356 
357     public static Object[] flatObjectArray(int length) {
358         Object[] result = new Object[length];
359         for (int i = 0; i < length; i++)
360             result[i] = Rnd.nextObject();
361         return result;
362     }
363 
364     // Calling this for length >> 100 is likely to run out of memory!  It
365     // should be perhaps be tuned to allow for longer arrays
366     public static Object[] nestedObjectArray(int length) {
367         Object[] result = new Object[length];
368         for (int i = 0; i < length; i++) {
369             switch(rnd.nextInt(16)) {
370                 case 0:  result[i] = nestedObjectArray(length/2);
371                          break;
372                 case 1:  result[i] = longArray(length/2);
373                          break;
374                 case 2:  result[i] = intArray(length/2);
375                          break;
376                 case 3:  result[i] = shortArray(length/2);
377                          break;
378                 case 4:  result[i] = charArray(length/2);
379                          break;
380                 case 5:  result[i] = byteArray(length/2);
381                          break;
382                 case 6:  result[i] = floatArray(length/2);
383                          break;
384                 case 7:  result[i] = doubleArray(length/2);
385                          break;
386                 case 8:  result[i] = longArray(length/2);
387                          break;
388                 default: result[i] = Rnd.nextObject();
389             }
390         }
391         return result;
392     }
393 }
394 
395 /**
396  * Primitive arrays viewed as lists.  Inefficient but cool.
397  * This utility should be generally useful in writing regression/unit/basic
398  * tests.
399  */
400 
401 class PrimitiveArrays {
402     public static List<Long> asList(final long[] a) {
403         return new AbstractList<Long>() {
404             public Long get(int i) { return a[i]; }
405             public int size()      { return a.length; }
406 
407             public Long set(int i, Long e) {
408                 long oldVal = a[i];
409                 a[i] = e;
410                 return oldVal;
411             }
412         };
413     }
414 
415     public static List<Integer> asList(final int[] a) {
416         return new AbstractList<Integer>() {
417             public Integer get(int i) { return a[i]; }
418             public int size()         { return a.length; }
419 
420             public Integer set(int i, Integer e) {
421                 int oldVal = a[i];
422                 a[i] = e;
423                 return oldVal;
424             }
425         };
426     }
427 
428     public static List<Short> asList(final short[] a) {
429         return new AbstractList<Short>() {
430             public Short get(int i) { return a[i]; }
431             public int size()       { return a.length; }
432 
433             public Short set(int i, Short e) {
434                 short oldVal = a[i];
435                 a[i] = e;
436                 return oldVal;
437             }
438         };
439     }
440 
441     public static List<Character> asList(final char[] a) {
442         return new AbstractList<Character>() {
443             public Character get(int i) { return a[i]; }
444             public int size()           { return a.length; }
445 
446             public Character set(int i, Character e) {
447                 Character oldVal = a[i];
448                 a[i] = e;
449                 return oldVal;
450             }
451         };
452     }
453 
454     public static List<Byte> asList(final byte[] a) {
455         return new AbstractList<Byte>() {
456             public Byte get(int i) { return a[i]; }
457             public int size()      { return a.length; }
458 
459             public Byte set(int i, Byte e) {
460                 Byte oldVal = a[i];
461                 a[i] = e;
462                 return oldVal;
463             }
464         };
465     }
466 
467     public static List<Boolean> asList(final boolean[] a) {
468         return new AbstractList<Boolean>() {
469             public Boolean get(int i) { return a[i]; }
470             public int size()         { return a.length; }
471 
472             public Boolean set(int i, Boolean e) {
473                 Boolean oldVal = a[i];
474                 a[i] = e;
475                 return oldVal;
476             }
477         };
478     }
479 
480     public static List<Double> asList(final double[] a) {
481         return new AbstractList<Double>() {
482             public Double get(int i) { return a[i]; }
483             public int size()        { return a.length; }
484 
485             public Double set(int i, Double e) {
486                 Double oldVal = a[i];
487                 a[i] = e;
488                 return oldVal;
489             }
490         };
491     }
492 
493     public static List<Float> asList(final float[] a) {
494         return new AbstractList<Float>() {
495             public Float get(int i) { return a[i]; }
496             public int size()       { return a.length; }
497 
498             public Float set(int i, Float e) {
499                 Float oldVal = a[i];
500                 a[i] = e;
501                 return oldVal;
502             }
503         };
504     }
505 }